
//    int setnonblocking(int fd);                             // 将fd设置为非阻塞
//    // 添加新用户(fd)， 第三个参数为true时设置为边缘触发
//    void addfd(int epollfd, int fd, bool enable_et);       
//    int epollDel(int fd, int epfd);                         // 删除epoll
//    int taskEnQueue(taskQueue_t *pTaskQueue, int netFd);    // 任务入队
//    int taskDeQueue(taskQueue_t *pTaskQueue);               // 任务出队
//    int tcpInit(char *ip, char *port, int *pSockFd)    
//    int factoryInit(factory_t *pFactory, int threadNum);    // 用于初始化factory对象的线程池
//   // 传输文件函数（未完善,函数体里的内容都可以修改，传输完成后设置runningFlag为0）
//    int transFile(int netFd);             
//    int handleEvent(int netFd, factory_t *pFactory);        // 线程要执行的操作
//    void cleanFunc(void *pArgs);                            // 线程清理
//    void* threadFunc(void *pArgs);
//    void makeWorker(factory_t *pFactory);                   // 用于线程池初始化，往线程池里创建线程

#include "func.h"
#include "function.h"

int setnonblocking(int fd)                              // 将fd设置为非阻塞
{
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

void addfd(int epollfd, int fd, bool enable_et)         // 添加新用户(fd)， 第三个参数为true时设置为边缘触发
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    if(enable_et)
        ev.events = EPOLLIN | EPOLLET;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
    setnonblocking(fd);                                // 设置为非阻塞
    printf("fd added to epoll\n");
}

int epollDel(int fd, int epfd)                         // 删除epoll
{
    int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
    ERROR_CHECK(ret, -1, "epoll_ctl del");
    printf("epollDel\n");
    return 0;
}

int taskEnQueue(taskQueue_t *pTaskQueue, int netFd)    // 任务入队
{
    task_t *pTask = (task_t *)calloc(1, sizeof(task_t));
    pTask->netFd = netFd;
    if(pTaskQueue->queueSize == 0)
    {
        pTaskQueue->pFront = pTask;
        pTaskQueue->pRear = pTask;
    }
    else
    {
        pTaskQueue->pRear->pNext = pTask;
        pTaskQueue->pRear = pTask;
    }
    ++pTaskQueue->queueSize;
    printf("taskEnQueue\n");
    return 0;
}

int taskDeQueue(taskQueue_t *pTaskQueue)           // 任务出队
{
    task_t *pCur = pTaskQueue->pFront;
    pTaskQueue->pFront = pTaskQueue->pFront->pNext;
    free(pCur);
    --pTaskQueue->queueSize;
    printf("taskDeQueue\n");
    return 0;
}

int tcpInit(char *ip, char *port, int *pSockFd)    
{
    *pSockFd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    bzero(&addr, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(atoi(port));
    int reuse = 1;
    int ret;
    ret = setsockopt(*pSockFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    ERROR_CHECK(ret, -1, "setsockopt");
    ret = bind(*pSockFd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
    ERROR_CHECK(ret, -1, "bind");
    ret = listen(*pSockFd, 10);
    ERROR_CHECK(ret, -1, "listen");
    return 0;
}

int factoryInit(factory_t *pFactory, int threadNum)                      // 用于初始化factory对象的线程池
{
    bzero(pFactory, sizeof(factory_t));
    pFactory->threadNum = threadNum;                                     // 设置线程池大小
    pFactory->tidArr = (pthread_t *)calloc(threadNum, sizeof(pthread_t));// 给线程池分配内存空间
    pthread_cond_init(&pFactory->taskQueue.cond, NULL);                  // 初始化任务队列条件量为空
    bzero(&pFactory->taskQueue, sizeof(taskQueue_t));                    // 给任务队列分配内存空间
    pthread_mutex_init(&pFactory->taskQueue.mutex, NULL);                // 初始化任务队列互斥量为空
    printf("factroyInit success\n");
    return 0;
}


int transFile(int netFd)               // 传输文件函数（未完善,函数体里的内容都可以修改，传输完成后设置runningFlag为0）
{
    train_s t = {5, "file2",0};
    t.size=5;
    send(netFd, &t, 4+5, MSG_NOSIGNAL);
    int fd = open(t.buf, O_RDONLY);
    ERROR_CHECK(fd, -1, "open");
    struct stat statbuf;
    fstat(fd, &statbuf);
    bzero(&t, sizeof(t));
    t.dataLength = sizeof(statbuf.st_size);
    memcpy(t.buf, &statbuf.st_size, t.dataLength);
    send(netFd, &t, sizeof(off_t) + 4, MSG_NOSIGNAL);
    sendfile(netFd, fd, NULL, statbuf.st_size);
    t.dataLength = 0;
    send(netFd, &t, 4, MSG_NOSIGNAL);
    close(fd);
    return 0;
}

int handleEvent(int netFd, factory_t *pFactory)             // 线程要执行的操作
{
    printf("handleEvent begin\n");
    transFile(netFd);                                       // 向netFd传输文件（未完善）
    close(netFd);
    if(pFactory->runningFlag == 0)                          // 传输完成的标准
    {
        puts("child exit");
        pthread_exit(NULL);                                 // 传输完成即退出该线程
    }
    printf("handleEvent end\n");
    return 0;
}

void cleanFunc(void *pArgs)                                 // 线程清理
{
    printf("cleanFunc\n");
    factory_t *pFactory = (factory_t *)pArgs;
    pthread_mutex_unlock(&pFactory->taskQueue.mutex);       // 解锁一个互斥量
}

void* threadFunc(void *pArgs)
{
    int netFd;
    while(1)
    {
        factory_t *pFactory = (factory_t *)pArgs;
        pthread_mutex_lock(&pFactory->taskQueue.mutex);     // 给任务队列加互斥锁,使后续执行队头任务时相关环境不会被并发执行的其他用户语句改变
        pthread_cleanup_push(cleanFunc, (void *)pFactory);  // 线程清理函数，当以非0参数调用pthread_cleanup_pop时被执行，此语句往后都是线程池退出时用到
        while(pFactory->taskQueue.queueSize == 0)           // 任务队列的大小为0时
        {
            pthread_cond_wait(&pFactory->taskQueue.cond, &pFactory->taskQueue.mutex);   // 等待任务队列的条件量和互斥量释放，即任务队列中没有正在执行的任务
            if(pFactory->runningFlag == 0)                  // facto对象没在运行时进入判断体，执行退出线程操作
            {
                puts("child exit");
                pthread_exit(NULL);                         // 退出线程
            }
        }
        printf("Get Task!\n");                              // 任务队列大小不为0，即未执行退出线程池操作时
        netFd = pFactory->taskQueue.pFront->netFd;          // 取任务队列的队头任务
        taskDeQueue(&pFactory->taskQueue);                  // 将任务队列队头任务出队
        pthread_cleanup_pop(1);                             // 线程池弹出一个线程
        handleEvent(netFd, pFactory);                       // 执行这个队头任务，以handleEvent函数指定的方式
        printf("pthread done! tid = %lu\n", pthread_self());// 执行成功标志
    }
}

void makeWorker(factory_t *pFactory)                        // 用于线程池初始化，往线程池里创建线程
{
    for(int i = 0; i < pFactory->threadNum; ++i)
    {
        pthread_create(pFactory->tidArr+i, NULL, threadFunc, (void *)pFactory);// 按照threadFunc函数（指针函数）方法给线程池tidArr数组的i位置创建一个线程
        printf("create thread %d success\n", i);
    }
}
